package com.neusoft.neuiotms.dcam.fixed.service.impl;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import javax.transaction.Transactional;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import com.neusoft.bizcore.web.constant.ExceptionConstants;
import com.neusoft.bizcore.web.exception.UnitedException;
import com.neusoft.bizcore.web.support.Searchable;
import com.neusoft.neuiotms.dcam.constant.DCAMConsts;
import com.neusoft.neuiotms.dcam.fixed.converter.InventoryPlanConverter;
import com.neusoft.neuiotms.dcam.fixed.dto.InventoryDutyHistoryDTO;
import com.neusoft.neuiotms.dcam.fixed.dto.InventoryPlanDTO;
import com.neusoft.neuiotms.dcam.fixed.dto.InventoryResultDTO;
import com.neusoft.neuiotms.dcam.fixed.model.Asset;
import com.neusoft.neuiotms.dcam.fixed.model.InventoryDuty;
import com.neusoft.neuiotms.dcam.fixed.model.InventoryPlan;
import com.neusoft.neuiotms.dcam.fixed.model.enums.InventoryDutyStatus;
import com.neusoft.neuiotms.dcam.fixed.model.enums.InventoryPlanStatus;
import com.neusoft.neuiotms.dcam.fixed.repository.AssetRepository;
import com.neusoft.neuiotms.dcam.fixed.repository.InventoryDutyRepository;
import com.neusoft.neuiotms.dcam.fixed.repository.InventoryPlanRepository;
import com.neusoft.neuiotms.dcam.fixed.repository.InventoryResultTemporaryRepository;
import com.neusoft.neuiotms.dcam.fixed.service.InventoryDutyHistoryService;
import com.neusoft.neuiotms.dcam.fixed.service.InventoryPlanService;
import com.neusoft.neuiotms.dcam.fixed.service.InventoryResultService;
import com.neusoft.neuiotms.dcam.fixed.util.SendingMessage;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class InventoryPlanServiceImpl implements InventoryPlanService {

    @Autowired
    private InventoryPlanRepository inventoryPlanRepository;
    @Autowired
    private InventoryPlanConverter inventoryPlanConverter;
    //    @Autowired
    //    private AssetService assetService;
    @Autowired
    private AssetRepository assetRepository;
    @Autowired
    private InventoryResultService inventoryResultService;
    //    @Autowired
    //    private InventoryResultConverter inventoryResultConverter;
    @Autowired
    private InventoryDutyRepository inventoryDutyRepository;

    @Autowired
    private InventoryResultTemporaryRepository inventoryResultTemporaryRepository;
    @Autowired
    private SendingMessage sendingMessage;
    @Autowired
    private InventoryDutyHistoryService inventoryDutyHistoryService;

    @Override
    public List<InventoryPlanDTO> findAll(final Searchable searchable) {
        final List<InventoryPlan> models = this.inventoryPlanRepository.search(searchable);
        return this.inventoryPlanConverter.toListDTO(models);
    }

    @Override
    public Page<InventoryPlanDTO> search(final Pageable pageable, final Searchable searchable) {
        final Page<InventoryPlan> models = this.inventoryPlanRepository.search(pageable, searchable);
        return this.inventoryPlanConverter.toPageDTO(models);
    }

    @Override
    public InventoryPlanDTO create(final InventoryPlanDTO dto) {
        InventoryPlan model = this.inventoryPlanConverter.toModel(dto);
        model = this.inventoryPlanRepository.save(model);
        return this.inventoryPlanConverter.toDTO(model);
    }

    @Override
    public InventoryPlanDTO details(final Long id) {
        final InventoryPlan model;
        try {
            model = this.inventoryPlanRepository.getOne(id);

            if (CollectionUtils.isEmpty(model.getDutyItems())) {
                final Optional<InventoryPlan> optPlan = this.inventoryPlanRepository.findById(id);
                if (optPlan != null) {
                    final InventoryPlan plan = optPlan.get();

                    if ((plan != null) && CollectionUtils.isNotEmpty(plan.getDutyItems())) {
                        model.setDutyItems(plan.getDutyItems().subList(0, plan.getDutyItems().size()));
                    }
                }
            }

        } catch (final Exception e) {
            throw new UnitedException(ExceptionConstants.ENTITY_NOT_FOUND, new Object[] {id });
        }
        return this.inventoryPlanConverter.toDTO(model, true);
    }

    @Override
    public void delete(final Long id) {

        final InventoryPlan model;
        try {
            model = this.inventoryPlanRepository.getOne(id);
        } catch (final Exception e) {
            throw new UnitedException(ExceptionConstants.ENTITY_NOT_FOUND, new Object[] {id });
        }

        // 如果已经下发的计划不能删除
        if (!InventoryPlanStatus.created.equals(model.getStatus())) {
            throw new UnitedException("只有已创建的状态下才能进行删除操作", new Object[] {id });
        }

        // 删除计划
        this.inventoryPlanRepository.deleteById(model.getId());
    }

    @Override
    public InventoryPlanDTO update(final Long id, final InventoryPlanDTO dto) {

        final InventoryPlan checkModel;
        try {
            checkModel = this.inventoryPlanRepository.getOne(id);
        } catch (final Exception e) {
            throw new UnitedException(ExceptionConstants.ENTITY_NOT_FOUND, new Object[] {id });
        }

        // 如果已经下发的计划不能变更
        if (!InventoryPlanStatus.created.equals(checkModel.getStatus())) {
            throw new UnitedException("只有已创建的状态下才能进行变更操作", new Object[] {id });
        }

        dto.setId(checkModel.getId());
        InventoryPlan model = this.inventoryPlanConverter.toModel(dto);

        model = this.inventoryPlanRepository.save(model);
        return this.inventoryPlanConverter.toDTO(model);
    }

    @Override
    @Transactional
    public void issue(final Long id) {

        final InventoryPlan model;

        try {
            model = this.inventoryPlanRepository.getOne(id);
        } catch (final Exception e) {
            throw new UnitedException(ExceptionConstants.ENTITY_NOT_FOUND, new Object[] {id });
        }

        if ((model.getDutyItems() == null) || (model.getDutyItems().size() <= 0)) {
            throw new UnitedException("计划中不含有任务,不能下发计划!");
        }

        final List<Long> dutyIdList = new ArrayList<>();
        // 查找所有的资产开始下发
        model.getDutyItems().stream().forEach(m -> {
            dutyIdList.add(m.getId());
        });

        for (final Long idl : dutyIdList) {
            // 更新子任务状态
            final InventoryDuty duty = this.inventoryDutyRepository.getOne(idl);
            if (duty != null) {
                duty.setStatus(InventoryDutyStatus.doing);
                this.inventoryDutyRepository.save(duty);
            }
            this.inventoryResultTemporaryRepository.deleteByInventoryDutyId(idl);

            this.inventoryDutyHistoryService.create(InventoryDutyHistoryDTO.builder().dutyCode(duty.getCode())
                    .comment("下发任务").status(0).createTime(Calendar.getInstance().getTime()).build());

            try {
                this.sendingMessage.SendImportResultToNotice("盘点任务提醒", duty.getAccount(), "您有新的盘点任务待执行");
            } catch (final Exception e) {
                InventoryPlanServiceImpl.log.error("", e);
            }
        }
        // 修改计划状态
        model.setStatus(InventoryPlanStatus.issued);
        this.inventoryPlanRepository.save(model);

    }

    @Override
    public void synchronousData(final String ids, final String rule) {
        this.inventoryResultService.synchronousData(ids, rule);
    }

    @Transactional
    @Override
    public void donePlan(final Long id) {
        InventoryPlan model;
        try {
            model = this.inventoryPlanRepository.getOne(id);
        } catch (final Exception e) {
            throw new UnitedException(ExceptionConstants.ENTITY_NOT_FOUND, new Object[] {id });
        }

        // 完成计划状态
        model.setStatus(InventoryPlanStatus.finish);
        model = this.inventoryPlanRepository.save(model);

        final List<InventoryDuty> dutyItems = model.getDutyItems().stream().collect(Collectors.toList());
        dutyItems.forEach(duty -> {
            duty.setStatus(InventoryDutyStatus.finish);
            this.inventoryDutyRepository.save(duty);
        });

        // 修改资产状态
        this.completePlan(id);

    }

    @Override
    public List<InventoryPlanDTO> findByStatus(final String status) {
        final List<InventoryPlan> models =
                this.inventoryPlanRepository.findByStatus(InventoryPlanStatus.valueOf(status));
        return this.inventoryPlanConverter.toListDTO(models);
    }

    /**
     * 计划完成后，需要更新资产状态
     *
     * @param planId
     */
    private void completePlan(final Long planId) {

        final Searchable searchable = new Searchable();
        searchable.put("planId", planId);
        final List<InventoryResultDTO> s = this.inventoryResultService.findAll(searchable);

        if (null != s) {
            final List<Asset> all = s.stream().map(l -> {
                Asset asset = null;
                switch (l.getDutyResultStatus()) {
                // 盘亏
                case loss:
                    asset = this.assetRepository.findByCode(l.getCode());
                    // 不确定设备是怎么丢失的
                    if (asset != null) {
                        asset.setStatus(DCAMConsts.ASSET_STATUS_LOSS);
                    }
                    break;

                // 盘盈（安徽项目里没有盘盈业务）
                case gain:
                    break;
                // 盘平
                case equality:
                    asset = this.assetRepository.findByCode(l.getCode());
                    // 变更位置
                    if (StringUtils.isNotBlank(l.getUpdateLocationCode())) {
                        asset.setLocation(l.getUpdateLocationCode());
                        asset.setLocationName(l.getUpdateLocationName());
                    }
                    // 变更组织
                    if (StringUtils.isNotBlank(l.getUpdateOrgCode())) {
                        asset.setManagementOrgCode(l.getUpdateOrgCode());
                        asset.setManagementOrgName(l.getUpdateOrgName());
                    }
                    // 变更人员
                    if (StringUtils.isNotBlank(l.getUpdateUserId())) {
                        asset.setManagementUserCode(l.getUpdateUserId());
                        asset.setManagementUserName(l.getUpdateUserName());
                    }
                    break;
                default:
                    break;
                }
                return asset;
            }).filter(k -> null != k).collect(Collectors.toList());

            if ((all != null) && (all.size() > 0)) {
                this.assetRepository.saveAll(all);
            }
        }

    }

}
